/////////////////////////////////////////////////////////////////////////
//                                                                     //
//    MTGProject - A Magic The Gathering Networked Environment         //
//                                                                     //
//      Copyright (c) 2008-2009 by The MTGProject Team (CSC230)        //
//                                                                     //
// This file is part of MTGProject.                                    //
//                                                                     //
// MTGProject is free software; you can redistribute it and/or         //
// modify it under the terms of the GNU Lesser General Public          //
// License as published by the Free Software Foundation; either        //
// version 3 of the License, or (at your option) any later version.    //
//                                                                     //
// This library is distributed in the hope that it will be useful,     //
// but WITHOUT ANY WARRANTY; without even the implied warranty of      //
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the       //
// GNU Lesser General Public License for more details.                 //
//                                                                     //
// You should have received a copy of the GNU Lesser General Public    //
// License along with this library; if not, write to the Free Software //
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA           //
// 02111-1307, USA, or contact the author(s):                          //
//                                                                     //
// Ruben Acuna <flyingfowlsoftware@earthlink.net>                      //
//                                                                     //
/////////////////////////////////////////////////////////////////////////

using System;
using System.Collections.Generic;
using System.Text;
using System.Net;

namespace MTGProject
{
    class Program
    {
        //Server Settings
        private static int SERVER_PORT = 8001;
        private static string SERVER_IP = "169.254.245.109";

        #region constructor

        public Program()
        {

        }

        #endregion

        #region entry point

        public static void Main()
        {
            Program server = new Program();

            char input = ' ';
            while (!input.Equals('a'))
            {
                System.Console.Clear();
                System.Console.WriteLine("The current IP is : " + SERVER_IP);
                System.Console.WriteLine("Press 'a' to accept, otherwise enter server IP.");
                input = System.Console.ReadKey(true).KeyChar;
                if (!input.Equals('a'))
                {
                    System.Console.Write(input);
                    SERVER_IP = input + System.Console.ReadLine();
                }
            }

            server.startServer(SERVER_IP, SERVER_PORT);

            System.Console.ReadLine();
        }

        #endregion

        #region methods

        public void startServer(string ip, int port)
        {
            GameServer mainServer = new GameServer(IPAddress.Parse(ip));
            GameServer.StatusChanged += new StatusChangedEventHandler(UpdateStatus);

            mainServer.StartListening();  
        }

        static private void UpdateStatus(object sender, StatusChangedEventArgs e)
        {
            System.Console.WriteLine(e.EventMessage + "\r");
        }

        static public void startGame(PlayerController player1, PlayerController player2)
        {
            Queue<PlayerController> players = new Queue<PlayerController>();

            //Generate instances of singletons in advance.
            CardMaster.getInstance();
            TheStack.getInstance();

            player1.Puppet.Enemy = player2.Puppet;
            player1.Puppet.PuppetMaster = player1;

            player2.Puppet.Enemy = player1.Puppet;
            player2.Puppet.PuppetMaster = player2;

            players.Enqueue(player1);
            players.Enqueue(player2);

            //foreach (ICard card in player1.Puppet.Deck.Cards)
            //        card.StartScript(player1);

            //foreach (ICard card in player2.Puppet.Deck.Cards)
            //        card.StartScript(player2);

            foreach (PlayerController player in players)
            {
                //shuffle
                player.Puppet.Deck.Shuffle();

                //draw hand
                player.Puppet.Hand.AddCardPool(player.Puppet.Deck.DrawCardPool(7));
            }

            Player loser = null;
            int turns = 0;

            while(loser == null)
            {
                PlayerController activeController = players.Dequeue();
                Player activePlayer = activeController.Puppet;

                turns++;

                System.Console.WriteLine(activePlayer.Name + "'s turn:");
                System.Console.WriteLine("The current turn is #" + turns + ".");

                //Rule: Player's untap all permanents at the start of their turn.
                foreach (IPermanent permanent in activePlayer.Permanents.Cards)
                    permanent.IsTapped = false;

                //Rule: Creatures heal at beginning of turn.
                foreach (ICard card in activePlayer.Permanents.Cards)
                    if(card is CardCreature)
                    ((CardCreature)card).Health = ((CardCreature)card).Toughness;

                //Rule: Summoning Sickness is removed during the first upkeep of it's controller.
                foreach (IPermanent permanent in activePlayer.Permanents.Cards)
                    if (permanent is CardCreature)
                        ((CardCreature)permanent).IsSick = false;

                //Rule: Each player draws one per turn. If they cannot draw, they lose.
                if (activePlayer.Deck.Cards.Count > 0)
                {
                    //Rule Exception: First player draws no card on first turn.
                    if (turns != 1)
                    {
                        ICard cardDrawn = activePlayer.Deck.Draw();
                        activePlayer.Hand.AddCard(cardDrawn);
                        System.Console.WriteLine("  " + activePlayer.Name + " draws a card (" + cardDrawn.Name + ").");
                    }
                }
                else
                    loser = activePlayer;

                #region SCRIPT HOOK - OnUpkeep

                IPermanent[] apPermanentsUpkeep = new IPermanent[activePlayer.Permanents.Cards.Count];
                activePlayer.Permanents.Cards.CopyTo(apPermanentsUpkeep, 0);
                for(int x = 0; x < apPermanentsUpkeep.Length; x++)
                    apPermanentsUpkeep[x].OnUpkeep(); //SCRIPT HOOK
                
                IPermanent[] enPermanentsUpkeep = new IPermanent[activePlayer.Enemy.Permanents.Cards.Count];
                activePlayer.Enemy.Permanents.Cards.CopyTo(enPermanentsUpkeep, 0);
                for (int x = 0; x < enPermanentsUpkeep.Length; x++)
                    enPermanentsUpkeep[x].OnUpkeep(); //SCRIPT HOOK

                #endregion

                //***Main Phase***
                activeController.PhaseMain();

                //***Combat Phase***
                activeController.PhaseCombat();

                //Rule: If creature has taken more damage than it's toughness, the creature is put into the graveyard.
                #region check player

                ICard[] possibleVictims = new ICard[activePlayer.Permanents.Cards.Count];
                activePlayer.Permanents.Cards.CopyTo(possibleVictims, 0);

                for(int x = 0; x < activePlayer.Permanents.Cards.Count; x++)
                {
                    ICard card = possibleVictims[x];
                    if ((card is CardCreature) && (((CardCreature)card).Health <= 0))
                    {
                        activePlayer.Permanents.RemoveCard(card);

                        if(!CardMaster.getInstance().IsToken(card))
                            activePlayer.Graveyard.AddCard(card);

                        ((CardCreature)card).OnDeath();

                        System.Console.WriteLine(card.Name + " is at " + ((CardCreature)card).Health);
                        System.Console.WriteLine("  " + activePlayer.Name +"'s " + card.Name + " died.");
                    }
                }

                #endregion

                #region check enemy

                possibleVictims = new ICard[activePlayer.Enemy.Permanents.Cards.Count];
                activePlayer.Enemy.Permanents.Cards.CopyTo(possibleVictims, 0);

                for (int x = 0; x < activePlayer.Enemy.Permanents.Cards.Count; x++)
                {
                    ICard card = possibleVictims[x];
                    if ((card is CardCreature) && (((CardCreature)card).Health <= 0))
                    {
                        activePlayer.Enemy.Permanents.RemoveCard(card);

                        if (!CardMaster.getInstance().IsToken(card))
                            activePlayer.Enemy.Graveyard.AddCard(card);

                        ((CardCreature)card).OnDeath();

                        System.Console.WriteLine("  " + activePlayer.Enemy.Name + "'s " + card.Name + " died.");
                    }
                }

                #endregion
                
                //Rule: Players lose if they have less than one health.
                if (activePlayer.Enemy.Health < 1)
                    loser = activePlayer.Enemy;

                //Rule: Mana Burn
                int manaBurn = activePlayer.ManaPool.Count;
                if (manaBurn > 0)
                {
                    activePlayer.TakeDamage(manaBurn, activePlayer);
                    System.Console.WriteLine("  " + activePlayer.Name + " took " + manaBurn + " damage from mana burn.");
                }
                activePlayer.ManaPool = new LinkedList<ManaColor>();

                //clean up temporary keywords and counters
                foreach(ICard creature in activePlayer.Permanents.Cards)
                    if (creature is CardCreature)
                    {
                        ((CardCreature)creature).TemporaryCountersOSO = 0;
                        ((CardCreature)creature).TemporaryKeywords = new LinkedList<CreatureKeyword>();
                    }

                players.Enqueue(activeController);
            }

            ((PlayerController)loser.PuppetMaster).OnLose();
            ((PlayerController)loser.Enemy.PuppetMaster).OnWin();

            System.Console.WriteLine(loser.Name + " lost after " + turns + " turns.");
        }
        

        #endregion
    }
}
